# -*- coding:utf-8 -*-
from bigchaindb import Bigchain
from bigchaindb.common import crypto
from bigchaindb.models import Transaction
from bigchaindb.common.transaction import Output, Input, TransactionLink
import time
import datetime
import asyncio
from blockchainrestful.money import Money


class Wallet(Money):
    # BLACKHOLE_PUB_KEY = "EtEsjpRedzezXsej1PsPBBCtHDL5LjBYXcJDQWHbhuFHCwNKSaWgKCyWoDy8jqTxNabt4QV5mrrpYt7qX9oZeHHGHonyHeozFnzoA"
    # BANK_PRIV_KEY = "CUZABR4aiN4VSCm52FLBzW2mw9XYYWoEw5wTygHQ6S9i5pVsWvJrrMsVtp5LuPRiizh28cG6G4UecQZgo7Y2Az9hk4siSGiRQA3rsv9V9PEFwWMTJNSZS8TshAhZQDfyQDupwVnFBvqyEgb1tctRkewFQbUBesV1A2oHAFDdqYocdSD2ji5mnLc3Ce8YmqayrDGz7YZS5rAaMk9CFhx1tCEytXJkLbEYorheUe9tC9wrfuJjqb2zZWUPpUFa9gYmVG5VhQgixqE4DgCpfAiTnUcXmcdWFzpCipbL67nBSEWzBBV4kaX1VDYYhCZeiBUuMZ31TBLWWmRaKomqt82zDWFpkds8DSjhbA7neufcw5UCF12xY62icLCZgU99dRqPLAsdecujWhqrLxSx4JtHwcwCruLxssKoU7LGwU7S5SQHVNt4zcKZH"
    # BANK_PUB_KEY = "EtEsjpSAK7Zc1i782Bvo8r8F7aeDRdfzAHAZbn9AAzKCv59mqWtBkrvEfP3i9hGgjTvzzsSZG3FqHty6Rh5gAMgvWQ7L9BV818tQg"
    # SUPER_PRIV_KEY = "4rZ3djVfXiXxejdbVKygt5jVHnzdM4ZqB77rJYDuueLzST5xYqUL33M21Zcqf9tgzj9ZBvDDzeTq4bveeg4v8W1efVEk3KYYz3RqbvwJAxsLLwCiohxiaoWkoEFKwJTLETgwNgD3aCU7b3ehnAMXj4Er2v94zDkx2CMNzj2UxWKpj2tgUU5Lfm6VkiCpFedZmtbyfMRXe2PRvwHwNSwQ2YzeKdk4KQmUTQEf5n6LTKRmp1A8PfJjbMgDmkxA72DN2P6v5cPWMs3p2Xe26vRyBFyMiGXLPjhst8mdfASyYW4qCYBwGUPnz6c2PLZBNLCbwuMK4fbPz45eWhxHWpqfgzo3Vd3qU1zwni6nv4ceVim8rGomxNfLpBcyBGTZ9r5Qfa69uw5mJQZVRYQpxQexYMnWcf4bnKN5x5fqUF7cq5kHjGpGfUC5gXHC"
    # SUPER_PUB_KEY = "EtEsjpSdV2dx28EuXUvrvCLXXtva4YAJ1dY2RZx71adBb7T87p3qDhrm6NaHekPQUZPcTPtNwxXGm4awWCU4Mmvfy3MGHxRfdtcMN"
    #
    # BLACKHOLE_PUB_KEY_NEW = "QynVvRdZByXUvvzTQVnfmqXfYQ2M6GY26YGSQzBS6sSqGGkTZfhyi4afiPLAFvhkAeJs38HUcR42iAHjHFxtZ2qznhDYvpuFBt9gtifWAjTuKJTL5ZgwHrUCB1B6mwCAiwSjoMW3wZRHdShNCvU3tvCXjZDVRiCk2ABeWXJrZDTZNXNXErTSoQjFAWodFEx"
    # BANK_PRIV_KEY_NEW = "M5vNR9uxJhiEtNEtRGhgXVtccGqHZoHgXd2WMM4nnhv9whQnzAmGBje3yPzbHYTHnfxH4YwcLEk2W3EbTCoY3xHCqMbw2XURQ6UrLv7b9bGJavbAoxmQgC1tQ9YEDsNjJ6SsUNWFzxAitp7ErBBec2sC4awG5zDKxKB8KEMBZN1qr3aFgSUuHdghya8q6LULetHFjU5BMefw8HzQDnxSyPPiX6gmCisqCuN4v8HDooPb1QRUoULLwzLyiVAeDpbNWipk9gFxB7H35YupD4GD5ijqBe1ccFgY7QYKMctGLAtf4suCUEHGGKjT3ES2fgfDiL8T4kxiSHsmuHf8CzfriZcvWCZu6JH3y4CfR5wXkErc1W8jr88vmfhMc1upua9NWGwps71ZiLhTiwGfUUBA9sPgBmDk3ob4qipJjWiZSeXMe5ReLh4r8QDnpQoUk9iaCi8tHXehbZgMRHbTZcC7EiW3eqvBEUVZKBT2mDpGHPVnGqDPxngPgD64GGLxW67Ppef9RY5csHf77wL6HigWkRd931CqJuikUoqCTPmDjGdwiJgbABs3WFTirWT7JwYEdHLN6d9WZsc7cM6KFEfBTYpS3mikY99A5dCA6fwYQTPyradeaqoJLRfkKDxU8qBf5yR3X9mco4NGdJr2EqzTn3Fm4S2goSqvuSPs6edu4GduuvY3Lv64dSTccqpFLRG6EbrRVHkbJDjPVJVP7giGW5A5BXxxGhJkYVSfT67UruttT5vu5oTZCvkH8cqnBG37VsmvYCjmCSCfAeZa2xCNzoF7LDpdeS2RYhox7DG5hohvsUvST69JrTUs8fy6FHBoZNfBK"
    # BANK_PUB_KEY_NEW = "QynVvRdZBxRRMzRNdPgC1HEY18p3xEYoScwuHy9mVZUzKcJeeF3qBPG1fAACqhMehdmpMtKNoRNtQRK1RKexwtF3CsYDHAQ2kjNgQaWVuEEDobq7McKh5AFL8R3ANCQg7K4bAt7Zt4H2Yeuaq6HbNB4Rh5dLB7vFicYChKPqtazJUfPzB3C7Yu6XWaFQPt4"
    # SUPER_PRIV_KEY_NEW = "M5vNR9uxJhiEtNF8ugE4ChdNpUu2LmZoChqocfQyTjUpcXA7ETxC3JjVN34y5rjejicog6jPNK2vPHDcTi3e1BFLWQidLH7i19Vw6s1ah84z1dYHyY3eGUV1BPLj6gbtBLjekqx9VHnUu5sNPTKqF39kpe32DuSG4PwZomT9tbGkQDfruHi1dRPDjA4gHAFbBwt8HjCLtKnficqBe2phdp8T7JQX5jFjEF7MT4CZPhXaBbgi6P9Wd6SGQv3gaPjczBYXgfiy6AYpQ6hiT3vnGMtCxMGmZ85JZVZN7h25T37UUaeDF6iTeT7RxPvBnB2TGJfp5P1obWT8YKoxw4sF8EtCPzecLKMQaUb6M1Ht2xA63yaNTUQTxbjtw8oJmumoeFLqHp3gZ4XszUFctAHYy7vai9636Rdi9Q5DR2EZuYgaPvpQ2TrgKeu2sAv4vDwx7CJRvoYz6E1XboQQVKoVKjUxjCUqcpVCT6gMXtMRCr4pSXzeeGADkMQyFJtfequExULbhDrg5SkjKbf8fAQq2wHSTkmzMRDAUimq4kXtbNYaMCHnzCB4dhp86zrMAursDpHqvMGsYvSQjGRXQo5wesFSsmb2XTrZtScz1zUa3Q5oyWcioFHtYdYWK1yCq8u4aAZbVwNPz1HoAaLST5AJUq483DPaqrnrNjVmVcc17pkpHY7XSiRzrC7sXmESwmdeXSTAC5TVgqpwvgkz2z92nzBiQSBwQzPmccp4zTp5gzrYoofytitqUjsSVGuJLpxZJmMCKRgUFcvVXeYBvCtXdFHGmR2EoxHNY4BMhUkAi8dJ4znCtsxC8KfQuoSc7p9vpSTAp"
    # SUPER_PUB_KEY_NEW = "QynVvRdZBzNdBdsfvF1fPX1uKz4bt1gwzMWjADQ7QSpTAZPS1GHdVp7FEzo4wRgHtE7YQsfBhn3iGDorRXEpogk4LVrrosTs3BN4Ub2rMjwFazZMqrv9RKvvJ4BPXY9TSmZ45oqZZBruv57jYRJiatu9Pm2rk3HzrsEi74bVse8xLBqgNmnfeDFSaR3ALqn"
    #
    # BLACKHOLE_PUB_KEY_2048 = "4e1BUTgGBfqVVdNJyBu2VqrsvXddBTZHbCN2JTfvtFwyBsUoK43GWNnY23UCgcRDNWWj5umJvvvya3dE6LSwQmF5jMoDVAhruAbkDiSqbUXW4E5h7EEvWmYmGXUHwwye7fyuUU7od1dRKy69jcfwLn3KBXQJWiPr9c3Y2h13sDWYcXr3oXDAJZHrHVQY4UKCJgvHo5Mv65uQAim8773hxp2JNmV7RQs46o5jXAWouVG4WHSrvoSKUF2cX1Q5vNnJR53qJxVnBSCmjHKz3piNGUtw17pKMxT4jNtg6meawcbgt1pT3Cb2LzSWioVYgzDpJjyoCLxWPw15jFodexKSdLUgfLacfpNZKWL3fSCpVX4q6cNRN"
    # BANK_PRIV_KEY_2048 = "4ABuuFEsjr4nnkY8LHBugmbrXpe4kHkoG6mZEbp4UDGtrFP1Do55FbwsaXSRNiaDKboGfjmKBAHpSPp94KgFJZhUddnivuQ3t88nZ9Nsmfx6so8XPVbToLWNxgbacXRpobRfXHVmqvvavQ2rvg1n8uf92mn8TLeMhNJwfxW1QPRLYyQcDebjaLpv17PPhY6TjcPbLWbtv9kR54g57jeyogCovtUZE33sip8SxZFcwP2rkTVDVzTBLKHhW8ivzRYir2kjgek7UFewzZ7nLpoxwgMPBrH44wdMD6o4kozzN4YBpjFFhrFGgfF5sEtJvoPRrcGHHEWRLyfEN93FLWzcgMK6KjEg7PZXKoucVPGJYtztKANQnoJKHFPquPb2KjMi3Sixua65DeJPRnDnTTNhJyNVU2HwuC1pCThgXMkAPY2KAZPkMVSihQTFKQtSA9FSAUuVn925s9SrSPg32ziZAikYzKgmP3TN8MPyQ33Q4iJCoWje5tyTkB9d3TMK7ioAeDQopS1FNXkoG6U28VerKbdzWYHhsxRtFtnNoALwFCZCvYEtosAhkgdsht7zjHufxPSCBSoKjNWqBVgF4d6AzfZBQiL6Jrps8Jm4Luhr7dkJ8gBaHL6A4GwPLxR6rkaUsf3RxntQapJKTzxNQKmGNZ73euL5JfN2mPQ5J52BeEftYfPQNDqpDvcGaKkEwHuwrqq4Wbet9hMVQUpq3VfzsSdFHWY7Xjci9Mssmg9Gce7qDKbdorZZSxTcLYPLefAYcpifdVZCGLKaAGPBouEPoPECkBASCMods9CdWnDsWknwD5pDoj8QQgZSU7hQQSdU7jzXAec2hF9k7q38EiKeYPVxMf2SP9AWMCwUSLLsd2AxiHoMsNKb5F6TzkmWeuWPAwEuEdKHcXrM3AePTC2N9KCKQ2vGMxKjd1uSfYmaqEeoten3k5jzMLGj9oh7wmihcxL6AVcDWZxiDWXkDZupyCRryBk3nzkzCntsFDy3ZZ8sLaKaqCcaPqXwhn7c5iDAKBzhJxezgb6wU1KRvCtCPriPSjwEb5sruvfCzenzWqjkjTYE8guHUP2Qy2XMZ4GKnc2cvD7XNvZ3WbGrkqBRmBnbRxkvKcdFa6E5Af7WDiaSXtnqrJqN9dZUSUQ7C7UvpUXiiVB8LaBekjtCLb3YSfkH4jvP33nY9hm4Jk5bsxJ47xHV7AqmvygmPVwKtHUFzdTDZF5Fcfv2Yzx7fz7NNNuoNu6JvQNJcgNz4x5YaLyBYTQY2u6tdyaqgLWxCkmjEhhQpW5HpyjbcykFym1LzQ4jthm8jyejkqpsr7aaMcAxBo5jsQ2yiNkC1WnfUqcg4dvnswGCpZKdu4e5JkGxrxHRnYCddvafPeUXnQqiXrcZEoZb37qR163ZJrmGwWpS494JKJq4FxnAxdbA7kZBaW8M1WvENSdLsZ9NtUp63XvZnq1kQkvheg8iX7tSM9xznfS7nKysdxgihUPQKgCUqSa2b9XFZ32eBWdAXpZB6fX2a1ePkgcUZoinnPv774om6dvSkTtqeExwD4h7rPQeb4x4ZTQ5TVK6a59pSeff2FuhKNBYg6mFfqZFJQTgs4dShkiUDGtTmTbDRm1bvz32AnECbygd6vSQZ9c"
    # BANK_PUB_KEY_2048 = "4e1BUTgGBfqVVptB3YDZ7kvjxFqewAM8svRfvjLPwDs4tUijw1b1bycwjC81YrZdNyASHfe3RbXwRMkyLvwSpfRZqd9R3fRZAvmCW8HAWRd516YgXRPquYo3PDCF6XmxZ5KMJcR2MJNW8jvAvdPbyd4B1gy14ohgH312faid63BxqX3Q9NUkdUQCMj5dXLvUCnkq9KTmnBpCPEKGkYhuHaDWo4bZWgs9ZPviF9RHHmX9dTP4S9gq89MZ2VKuZSD67QGiF7eKMGeTN9qXLpkjLNvyXN9AYP7N25KCmHap6n89cTuFAMSVEAuZNsmfzSVy3Sa4VkBjfN8V7cKvcqtZP8nQEKu1q6awWAd6bZGtTrcVWCe3J"
    # SUPER_PRIV_KEY_2048 = "4ABuuFEsjr4nnkY8LZPUSYSzfX6qB4bzMNzij7jxgL61GxYG5DspjHD4T5NXFwQxFbYdRzr43NZPMzEqH9HZYrhpw8kNG6HKQv3ibueqeVWvPP1pcqRY9cVmUq3vCsFKpLS2xcQ55Dv5mSNyjgiveDo9MRdGvjsVgNyTGB5DxCGRVRWfgPaHudhzdewCo8Evdn8VD6PD8dnSGbnQeMB5zvXctJ8RNi9KgJxKwzs1PJqyP382nSyW36p7aF14mRerYLyxRznDnGNDQzh9LgMY242GCmZMkwqVRsRFn2vg5q8YdbBMwccY5gXy3z9nWKuiEvTGNvzVnWbRDFhaJTX8WRSGfkpExdjHxAiVhN69UnwaSPJdZacJ9kan1k6qk4czRE8jtF2QBqMtCbJYDW6HfVbK3kAFXdxe4RvJed7WTSm8fY4AM9mZNdRsz1kE2vDCXumj7PQKMUA6w2zyLeJJAgkQBQ9pp8gpcxi2WUBZsJCLbyk6MB6J52V2zBjFq96RpXo19LkpqcmJbDUK6jQcChu8Wa4HfJsD338F6zfzCXwaZ4ii1GG5Cbh3ccVfrz5cpqDZz5EP4qTEXh5unq12dateKEXZEWWwFRG18A3tDt1HJM38Amv9TEJ2rKMpVQ6zcxubqh8AFhLxqysKMGKc29KFWC4HXMThwrqHpyCYG8kTTU3sKgYDmUKPF6NZNFoY4r1gPVBZSPeifLfoYYZbs1SHL9DhhqAtgHiwmVrNs2NLwYPJpmWiKpj38VkoBpvGUvFdksKgLd56jeCgsSKrTsKh33yjHYzn5RD77NQ9EaWixbMp2N5ADNQw1NyAkwXq1MXhmD6Txvkuj3HL56qe4c2YMwyMXny1fbxZ7Ef4FU2rLJJy5QPnDh2kicss6Sh8z3X8DEuaCjRbPyY7fxNgFfNqncSkH3c3xipAtMMyocAeTeSELSuN1LL8fX21aobWDukjpZuwhxwWTmMHW7njyguv5oR2recvEaFAt5B6B27NhHePzwwWNVfdUHALMwLG3DSrwow9SiWW5y9uDTJ8kjMxecPGhdGYYssbwRsM8LEpiVkuvCHsrygkwFKbTE4p1wLaLRyHhiV4vwGkycUgtboDL45hhsvbkiBwsSmuga1YmRwkiCENr7azcXf2LQ7u9LaKYaLzQJqK48BnNc7g4THXWKpYkyELHgYqVAP3ES7ajioZqnsK9EqHwTShUNZgJJLDtu7k2WErwmQPN2DcjUy7RgSLVJWA9QG7kWp7EebVW9M73c2QfRfB7TZxHKY5n2mL8RNM8cvX8EX61qmXdxifo2wSVNVBxKr33wX61aNEm1NTZiBF2THWjwRBVtQyDTaNh2qap2AY2d15Aqddiy3Wh75zWz6yunwx9pWo6Mf3Gridvq5qr8J96xbUN3ffx6SUHqRhBUzwS4MFThVwB2NJf3WvGEcEsViKxGcwNKYe4CBvsYtsN8gNFq6TJYV34JL5cgJzvnGGLnibME9zBzeC77G5uHbRgxxkm61VegeVRweQsYvf6rhjQ9iDyTUMN5Njoyfe9ig7Nm8LmNNQSjVK8PJdJXHcvR5XfUFDaeQCFTCnELmaAUUStG7mQbZ4B4CYRbCDC2PB3K64VexQkC2DjAehiZpFnW6"
    # SUPER_PUB_KEY_2048 = "4e1BUTgGBfqVWJYdEvRy6uieukQa9HeJ9RbmhryEvXEAnTu45Ln55sWaDvsbLq5kHs1UUwkmUtFR6CfmkZHSFV6MHnhEuSwTQVHFHrj5s8eZczipGtwLFw3Lz5NGTWcnr7q4xSA4LsrgSGEWLChjJNp1bLxpwXEbSHJmhkmn69LSxUS8WG6wACaXgznxVKp4fk3tAxgTBQrfnuZNpmFMriiCmg96f445pkZodD3m8DvHcuhmXM4yNhtxHd8gxNAvNMFXE54DSrsofSuT4VcfN46URVE4qboNfaX2ZR3PSq4ogcD9KMTi87fqWFjcMaUD8pBodAKRrYktSnXDNir1vVzGhzfRsBocskycfeRM5ns9UapM6"
    #
    # ASSET_AGGRE_THRESHOLD = 10
    # ASSET_TYPE = {'money': 'money RMB', 'bill': 'bill'}
    # TRANSAC_TYPE = {'aggre': 'asset aggregation', 'tran': 'transfer', 'roll': 'rollback', 'chong': 'chongzheng'}
    # TIMEOUT = 30

    def __init__(self):
        self.b = Bigchain()
        self.asset = {'asset': self.ASSET_TYPE['money']}

    def filter_by_aggregation_asset(self, txs, indexs):
        filtered_txs = []
        filtered_indexs = []
        for i in range(len(txs)):
            if not self.b.is_tx_strictly_in_invalid_block(txs[i]['id']):
                filtered_txs.append(txs[i])
                filtered_indexs.append(indexs[i])
                if 'type' in txs[i]["metadata"] and txs[i]["metadata"]['type'] == self.TRANSAC_TYPE['aggre']:
                    break
        return (filtered_txs, filtered_indexs)

    def get_unspent_outputs(self, owner):
        output_txs, output_indexs = self.b.get_tx_outputs_filter_by_aggregation_asset(owner)
        # output_txs, output_indexs = self.b.get_tx_outputs(owner)
        input_txs, input_indexs = self.b.get_tx_inputs_filter_by_aggregation_asset(owner)
        # input_txs, input_indexs = self.b.get_tx_inputs(owner)
        # output_txs, output_indexs = self.filter_by_aggregation_asset(output_txs, output_indexs)
        # input_txs, input_indexs = self.filter_by_aggregation_asset(input_txs, input_indexs)
        txs = []
        indexs = []
        for i in range(len(output_txs)):
            spent = False
            for j in range(len(input_txs)):
                input = input_txs[j]["inputs"][input_indexs[j]]
                if input["fulfills"]["txid"] == output_txs[i]["id"] and input["fulfills"]["output"] == output_indexs[i]:
                    spent = True
                    break
            if not spent:
                txs.append(output_txs[i])
                indexs.append(output_indexs[i])
        return (txs, indexs)

    def go_through_all_assets(self, account):
        txs, indexs = self.get_unspent_outputs(account)
        # translinks = self.b.get_owned_ids(account)
        total = 0
        account_sets = []
        for i in range(len(txs)):
            # for translink in translinks:
            try:
                tx = Transaction.from_dict(txs[i])
            except Exception as e:
                print('Invalid Transaction: %s', e)
                continue
            index = indexs[i]
            asset_id = tx.id
            if 'id' in tx.asset:
                asset_id = tx.asset['id']
            if tx.metadata['asset'] == self.ASSET_TYPE['money']:
                total = total + tx.outputs[index].amount
                account_sets.append({"translink": TransactionLink(tx.id, index),
                                     "tx": tx,
                                     "asset_id": asset_id,
                                     "amount": tx.outputs[index].amount})
        return (total, account_sets)

    def get_assets(self, account, txid):
        txs, indexs = self.get_unspent_outputs(account)
        account_set = {}
        for i in range(len(txs)):
            tx = Transaction.from_dict(txs[i])
            if tx.id == txid:
                index = indexs[i]
                asset_id = tx.id
                if 'id' in tx.asset:
                    asset_id = tx.asset['id']
                if tx.metadata['asset'] == self.ASSET_TYPE['money']:
                    account_set = {"translink": TransactionLink(tx.id, index),
                                   "tx": tx,
                                   "asset_id": asset_id,
                                   "amount": tx.outputs[index].amount}
                break
        return (index, account_set)

    # modify the owner to the first one, change the weight and threshold
    def conv_output(self, orig_output):
        orig_output.public_keys = [orig_output.public_keys[0]]
        output = orig_output.to_dict()
        output['condition']['details']['threshold'] = len(output['condition']['details']['subfulfillments']) - 1
        for j in range(len(output['condition']['details']['subfulfillments'])):
            if output['condition']['details']['subfulfillments'][j]['public_key'] == orig_output.public_keys[0]:
                output['condition']['details']['subfulfillments'][j]['weight'] \
                    = output['condition']['details']['threshold']
        return Output.from_dict(output)

    # wait until all the tx are successful or timeout
    def wait_for_tx_result(self, tx_ids, timeout):
        print('-wait_for_tx_result---tx_ids----', tx_ids)
        count = 0
        while True:
            interval = 0.2
            time.sleep(interval)
            ret = True
            err_txids = []
            succ_txids = []
            cout = 0
            for txid in tx_ids:
                temp, status = self.b.get_transaction(txid, include_status=True)
                if status == self.b.BLOCK_INVALID:
                    cout = cout + 1
                    ret = False
                    err_txids.append(txid)
                elif status == self.b.TX_VALID:
                    cout = cout + 1
                    succ_txids.append(txid)
                else:
                    ret = False
                    err_txids.append(txid)
            if ret:
                return {"ret": True, "succ_txids": succ_txids}
            count = count + interval
            if count >= timeout or cout == len(tx_ids):
                print('-wait_for_tx_result---err_txids----', err_txids)
                for txid in err_txids:
                    self.b.delete_transaction(txid)
                return {"ret": False, "err": "交易失败", "succ_txids": succ_txids}

    def get_total_money(self, account):

        total, account_sets = self.go_through_all_assets(account)
        amounts = []
        for account_set in account_sets:
            amounts.append(account_set["amount"])
        print(amounts)
        return total

    def deposit_money(self, account, amount, metadata=None, timeout=Money.TIMEOUT):
        meta = {'group': time.time(), 'asset': self.ASSET_TYPE['money']}
        if metadata != None:
            meta.update(metadata)

        total, account_from_sets = self.go_through_all_assets(account)
        if len(account_from_sets) >= self.ASSET_AGGRE_THRESHOLD:
            print('---------deposit_money---aggre_asset----------')
            ret, account_from_set = self.aggre_asset(account, total, account_from_sets)
            if not ret["ret"]:
                self.rollback(ret['succ_txids'])

        meta['group'] = time.time()
        tx = Transaction.create([self.BANK_PUB_KEY_NEW], [([account, self.BANK_PUB_KEY_NEW, self.SUPER_PUB_KEY_NEW], amount)],
                                asset=self.asset, metadata=meta)

        for i in range(len(tx.outputs)):
            tx.outputs[i] = self.conv_output(tx.outputs[i])

        tx = tx.sign([self.BANK_PRIV_KEY_NEW])
        self.b.write_transaction(tx)

        return self.wait_for_tx_result([tx.id], timeout)

    def aggre_asset(self, account, total, account_sets, timeout=Money.TIMEOUT):
        meta = {'group': time.time(), 'asset': self.ASSET_TYPE['money'], 'type': self.TRANSAC_TYPE['aggre']}
        tx_ids = []
        amounts = []
        for account_set in account_sets:

            superprikey = self.SUPER_PRIV_KEY_NEW
            bankprikey = self.BANK_PRIV_KEY_NEW

            idx = account_set["translink"].output
            txfrom = self.b.get_transaction(txid=account_set["tx"].id).to_dict()
            subfulfillments = txfrom['outputs'][idx]['condition']['details']['subfulfillments']
            if len(subfulfillments) > 2:
                if len(subfulfillments[2]['public_key']) > 300:
                    bankprikey = self.BANK_PRIV_KEY_2048
                elif len(subfulfillments[2]['public_key']) > 130:  # len(old pubkey)==101  ; len(new pubkey)==191
                    superprikey = self.SUPER_PRIV_KEY_NEW
                else:
                    superprikey = self.SUPER_PRIV_KEY

            if len(subfulfillments) > 1:
                if len(subfulfillments[1]['public_key']) > 300:
                    bankprikey = self.BANK_PRIV_KEY_2048
                elif len(subfulfillments[1]['public_key']) > 130:
                    bankprikey = self.BANK_PRIV_KEY_NEW
                else:
                    bankprikey = self.BANK_PRIV_KEY

            recipients = [([self.BLACKHOLE_PUB_KEY_NEW], account_set["amount"])]
            # idx = account_set["translink"].output
            transfer_inputs = [Input(account_set["tx"].outputs[idx].fulfillment,
                                     account_set["tx"].outputs[idx].public_keys,
                                     TransactionLink(account_set["tx"].id, idx))]
            tx = Transaction.transfer(transfer_inputs, recipients,
                                      account_set["asset_id"], metadata=meta)
            tx = tx.sign([bankprikey, superprikey])
            self.b.write_transaction(tx)
            tx_ids.append(tx.id)
            amounts.append(account_set["amount"])

        tx = Transaction.create([self.BANK_PUB_KEY_NEW], [([account, self.BANK_PUB_KEY_NEW, self.SUPER_PUB_KEY_NEW], total)],
                                asset=self.asset, metadata=meta)

        for i in range(len(tx.outputs)):
            tx.outputs[i] = self.conv_output(tx.outputs[i])

        tx = tx.sign([self.BANK_PRIV_KEY_NEW])
        self.b.write_transaction(tx)
        tx_ids.append(tx.id)
        account_set = {"translink": TransactionLink(tx.id, 0),
                       "tx": tx,
                       "asset_id": tx.id,
                       "amount": total}
        return (self.wait_for_tx_result(tx_ids, timeout), account_set)

    def transfer_single_transaction(self, account_from, account_to, account_from_set, amount, metadata=None,
                                    keyfree=True):

        superpubkey = self.SUPER_PUB_KEY_NEW
        superprikey = self.SUPER_PRIV_KEY_NEW

        bankpubkey = self.BANK_PUB_KEY_NEW
        bankprikey = self.BANK_PRIV_KEY_NEW

        idx = account_from_set["translink"].output
        txfrom = self.b.get_transaction(txid=account_from_set["tx"].id).to_dict()
        subfulfillments = txfrom['outputs'][idx]['condition']['details']['subfulfillments']
        if len(subfulfillments) > 2:
            if len(subfulfillments[2]['public_key']) > 300:  # len(old pubkey)==101  ; len(new pubkey)==191
                superpubkey = self.SUPER_PUB_KEY_2048
                superprikey = self.SUPER_PRIV_KEY_2048
            elif len(subfulfillments[2]['public_key']) > 130:  # len(old pubkey)==101  ; len(new pubkey)==191
                superpubkey = self.SUPER_PUB_KEY_NEW
                superprikey = self.SUPER_PRIV_KEY_NEW
            else:
                superpubkey = self.SUPER_PUB_KEY
                superprikey = self.SUPER_PRIV_KEY

        if len(subfulfillments) > 1:
            if len(subfulfillments[1]['public_key']) > 300:
                bankpubkey = self.BANK_PUB_KEY_2048
                bankprikey = self.BANK_PRIV_KEY_2048
            elif len(subfulfillments[1]['public_key']) > 130:
                bankpubkey = self.BANK_PUB_KEY_NEW
                bankprikey = self.BANK_PRIV_KEY_NEW
            else:
                bankpubkey = self.BANK_PUB_KEY
                bankprikey = self.BANK_PRIV_KEY

        print('bankpubkey:{}\nsuperpubkey:{}'.format(bankpubkey, superpubkey))
        recipients = [([account_to, bankpubkey, superpubkey], amount)]
        if account_from_set["amount"] > amount:
            recipients.append(
                ([account_from, bankpubkey, superpubkey], account_from_set["amount"] - amount))

        transfer_inputs = [Input(account_from_set["tx"].outputs[idx].fulfillment,
                                 account_from_set["tx"].outputs[idx].public_keys,
                                 TransactionLink(account_from_set["tx"].id, idx))]

        # recipients contains bank and super's pub_keys, bigchain generate threshold condition in outputs
        tx = Transaction.transfer(transfer_inputs, recipients,
                                  account_from_set["asset_id"], metadata=metadata)

        for i in range(len(tx.outputs)):
            tx.outputs[i] = self.conv_output(tx.outputs[i])
        if keyfree:
            tx = tx.sign([bankprikey, superprikey])
            # print('---------self.haha-------------', self.haha)
            # if self.haha == 100:
            #     tx.inputs[0].fulfillment.subconditions[0][
            #         'body'].signature = b'g3L|\xd8\x86\xbb%\xa4\xaaZ\xac\xae\x95\x00\x8f\x93\x06\xa9T\xc6se\xbd\x86\xec\xc8S\x9e\x8f%O\t#Uk\xf4\x8e\xfdzQ\x1f\xbd`\x99\xe7\x8d5\x1c\xb9)\xf0_Jf\xf1\xe3\x8c\xf19\x03{\xc3\x00'

            self.b.write_transaction(tx)
            return tx.id
        else:
            self.b.write_unsigned_transaction(tx)
            return tx.id

    # haha = 0

    def transfer_money(self, account_from, account_to, amount, metadata=None, timeout=Money.TIMEOUT, keyfree=True):
        meta = {'group': time.time(), 'asset': self.ASSET_TYPE['money']}
        if metadata != None:
            meta.update(metadata)
        total, account_from_sets = self.go_through_all_assets(account_from)
        if total < amount:
            return {"ret": False, "err": "余额不足"}
        if len(account_from_sets) >= self.ASSET_AGGRE_THRESHOLD:
            print('--------aggre_asset----------')
            ret, account_from_set = self.aggre_asset(account_from, total, account_from_sets)
            if not ret["ret"]:
                self.rollback(ret['succ_txids'])
                return ret

            meta['group'] = time.time()
            txid = self.transfer_single_transaction(account_from, account_to, account_from_set,
                                                    amount, metadata=meta, keyfree=keyfree)
            if keyfree:
                return self.wait_for_tx_result([txid], timeout)
            else:
                return [txid]

        money_left = amount
        tx_ids = []

        meta['group'] = time.time()
        for account_from_set in account_from_sets:
            transfer_amount = min(account_from_set["amount"], money_left)
            txid = self.transfer_single_transaction(account_from, account_to, account_from_set,
                                                    transfer_amount, metadata=meta, keyfree=keyfree)
            tx_ids.append(txid)
            if account_from_set["amount"] > money_left:
                money_left = 0
            else:
                money_left = money_left - account_from_set["amount"]
            if money_left == 0:
                break
        if keyfree:
            ret = self.wait_for_tx_result(tx_ids, timeout)
            if not ret["ret"]:
                self.rollback(ret['succ_txids'])
            return ret
        else:
            return tx_ids

    # @asyncio.coroutine
    def rollback(self, succ_txids):
        print('----coroutine start-----')
        self.dorollback(succ_txids)
        # yield from self.dorollback(succ_txids)

        print('rollback ok!')

    def dorollback(self, succ_txids):
        for succ_txid in succ_txids:

            while True:
                tx = self.b.get_transaction(txid=succ_txid)
                print('---dorollback--tx-->', tx)

                for output in tx.outputs:
                    if output.public_keys[0] == tx.inputs[0].owners_before[0]:
                        pass
                    else:
                        account_from = output.public_keys[0]
                        amount = output.amount

                account_to = tx.inputs[0].owners_before[0]
                ########################################
                if tx.operation == 'CREATE':  #
                    meta = {'group': time.time(), 'asset': self.ASSET_TYPE['money'], 'type': self.TRANSAC_TYPE['roll']}
                    recipients = [([self.BLACKHOLE_PUB_KEY_NEW], amount)]
                    idx = 0

                    superprikey = self.SUPER_PRIV_KEY_NEW
                    bankprikey = self.BANK_PRIV_KEY_NEW

                    txfrom = tx.to_dict()
                    subfulfillments = txfrom['outputs'][idx]['condition']['details']['subfulfillments']
                    if len(subfulfillments) > 2:
                        if len(subfulfillments[2]['public_key']) > 130:  # len(old pubkey)==101  ; len(new pubkey)==191
                            superprikey = self.SUPER_PRIV_KEY_NEW
                        else:
                            superprikey = self.SUPER_PRIV_KEY

                    if len(subfulfillments) > 1:
                        if len(subfulfillments[1]['public_key']) > 130:
                            bankprikey = self.BANK_PRIV_KEY_NEW
                        else:
                            bankprikey = self.BANK_PRIV_KEY

                    transfer_inputs = [Input(tx.outputs[idx].fulfillment,
                                             tx.outputs[idx].public_keys,
                                             TransactionLink(tx.id, idx))]
                    tx = Transaction.transfer(transfer_inputs, recipients,
                                              tx.id, metadata=meta)
                    tx = tx.sign([bankprikey, superprikey])
                    self.b.write_transaction(tx)
                    ret = self.wait_for_tx_result([tx.id], 30)
                else:
                    # if 'to' in tx.metadata and 'phone' in tx.metadata['to']:  # phone to phone
                    #     ret = self.transfer_money(account_from=account_from, account_to=account_to, amount=amount)
                    # else:  # to black hole
                    #     ret = self.deposit_money(account=account_to, amount=amount)

                    meta = {'group': time.time(), 'asset': self.ASSET_TYPE['money'], 'type': self.TRANSAC_TYPE['roll']}
                    if account_from == self.BLACKHOLE_PUB_KEY or \
                                    account_from == self.BLACKHOLE_PUB_KEY_NEW:  # to black hole
                        ret = self.deposit_money(account=account_to, amount=amount, metadata=meta)
                    else:  # phone to phone
                        meta['to'] = tx.metadata['from']
                        meta['from'] = tx.metadata['to']
                        idx, ass = self.get_assets(account_from, tx.id)
                        txid = self.transfer_single_transaction(account_from, account_to, ass, amount, meta)
                        ret = self.wait_for_tx_result([txid], 30)
                        # ret = self.transfer_money(account_from=account_from, account_to=account_to, amount=amount,metadata=meta)

                if ret['ret']:
                    print('------break--------', tx.id)
                    break
                else:
                    if len(ret['succ_txids']) > 0:
                        self.dorollback(ret['succ_txids'])
                            # if su:
                            #     return False


if __name__ == "__main__":
    A_priv_key = "secwXg4244u8eKjxU8ig8JNhLQB7o4siT5EUzmk1diJgVShwY1n2Y8Du6Xb1rf75EBFHFwv8kyfs2sHmUwYJunK3kcKANbkWWp3YK33GBDrH7LjhtE26BhXKPQqPpo2ZQrNb17s7gkhYzoAynYdN9r91bHnvGxXn9qyW42Z8FVpmFG5NjKjhDr5NxHCRwgjn4U1HFnQGvz6SewMaoZ93rjddbLboZ8fVjstydKZQvgc7hLMqSZB6h83vECrrw2cUz7AfTq359MLPi9dqXHVxTf8cFSh9BwZeQ2rm5ZwDeMbvMC6xCHN8pgThgixiytj11uvFbhvMjenQ89US2YgJM96g6449fhWwP2hvrsr2c6K8SaLkys67BxBWRWyF9A79rqJdBx8oFmyFV1eRzfd8t8kQQZNSwBiH8bmiY4BMkmdazsGNqdWAMg"
    A_pub_key = "EtEsjpSCbwXpAZwEb5i9tBQLjdDbLLmhtv8ePW7QJDr5kvhRH4MahfMkUeevT48ktYb2PM84w71dYvDq7d5oMQQgfS3S8tPmk93hz"

    B_priv_key = "secwXg4244u8eLaWb8YqByae63ehpk9ui1eL6n1ouPqcsFUcPqLA2mfQJxYMgNwVBi32DimmH2nNrHjb1UKY7gQP2BJoAyr2WvyGsaEhbVs2WMCxctfKwWuaaSXeGHK15oAmu3Qni2rpADFdL4676afZGqSSWFijAFqYUEGyQpPHXztzda4b1UUdpEuwzKfKV1zxFnhqNjgRkdcspcDWjNMmsSJKWaojjHZg7ir4kESwmMNGRUew5D7dQA752MrXWRVdGrYwhksJms2nNkgM4MuF4zUudUQTvP3d9LBmT1fF5du3KSpfMDEZaoGXgKkMW8ufiHxibqdxgZ3kn1W8pVZ4PeuJLErT6cq9RqRj8XYC6irB6Amr5dJBgypiEwH9y97tMaBmTwDZMKG86DSdg7CCjee28wxLBDE1KL3LKneX5U8FaksB4B"
    B_pub_key = "EtEsjpSKG9QLaXrB7zkStRtGhb98UoeGa2wB7QP9LxjPohdeBsULY4fLnphuFednpgc3fZ63iUhUeQVVkyq8JDmRCazQzamfsSNDE"

    wallet = Wallet()
    # print("--------------------------------")
    # print("At the beginning:")
    # print("A's money: ")
    # time_A = time.time()
    # money_A_begin = wallet.get_total_money(A_pub_key)
    # print("Total: " + str(money_A_begin))
    # time_B = time.time()
    # print("A's money query time: %f" % (time_B - time_A))
    # print("B's money: ")
    # money_B_begin = wallet.get_total_money(B_pub_key)
    # print("Total: " + str(money_B_begin))
    # time_C = time.time()
    # print("B's money query time: %f" % (time_C - time_B))
    # print("--------------------------------")
    # amount = 40
    # print("Deposit to A: $%d" % amount)
    # time_A = time.time()
    # meta = {
    #     "from": {
    #         "name": "张三",
    #         "bank": "招商银行",
    #         "account": "6214888888888888"
    #     },
    #     "time": datetime.datetime.now().strftime('%Y/%m/%d%H: %M: %S'),
    #     "comment": "房租"
    # }
    # ret = wallet.deposit_money(A_pub_key, amount, metadata=meta)
    # if not ret["ret"]:
    #     print(ret["err"])
    # time_B = time.time()
    # print("A's deposit time: %f" % (time_B - time_A))
    # print("A's money: ")
    # time_A = time.time()
    # money_A_step1 = wallet.get_total_money(A_pub_key)
    # print("Total: " + str(money_A_step1))
    # time_B = time.time()
    # print("A's money query time: %f" % (time_B - time_A))
    # print("B's money: ")
    # money_B_step1 = wallet.get_total_money(B_pub_key)
    # print("Total: " + str(money_B_step1))
    # time_C = time.time()
    # print("B's money query time: %f" % (time_C - time_B))
    # if money_A_step1 - money_A_begin == amount:
    #     print("Check pass")
    # else:
    #     print("Check fail")
    # print("--------------------------------")
    #
    # amount = 37
    # print("A pays to B: $%d" % amount)
    # time_A = time.time()
    # meta = {
    #     "from": {
    #         "name": "张三",
    #         "phone": "13700000000"
    #     },
    #     "to": {
    #         "name": "李四",
    #         "phone": "13800000000"
    #     },
    #     "time": datetime.datetime.now().strftime('%Y/%m/%d%H: %M: %S'),
    #     "comment": "转账"
    # }
    # ret = wallet.transfer_money(A_pub_key, B_pub_key, amount, metadata=meta)
    # if not ret["ret"]:
    #     print(ret["err"])
    # time_B = time.time()
    # print("Money transfer time: %f" % (time_B - time_A))
    # print("A's money: ")
    # time_A = time.time()
    # money_A_step2 = wallet.get_total_money(A_pub_key)
    # print("Total: " + str(money_A_step2))
    # time_B = time.time()
    # print("A's money query time: %f" % (time_B - time_A))
    # print("B's money: ")
    # money_B_step2 = wallet.get_total_money(B_pub_key)
    # print("Total: " + str(money_B_step2))
    # time_C = time.time()
    # print("B's money query time: %f" % (time_C - time_B))
    # if money_A_step1 - money_A_step2 == amount and money_B_step2 - money_B_step1 == amount:
    #     print("Check pass")
    # else:
    #     print("Check fail")
    # print("--------------------------------")
    #
    # amount = 27
    # print("B pays to A: $%d" % amount)
    # time_A = time.time()
    # meta = {
    #     "from": {
    #         "name": "李四",
    #         "phone": "13800000000"
    #     },
    #     "to": {
    #         "name": "张三",
    #         "phone": "13700000000"
    #     },
    #     "time": datetime.datetime.now().strftime('%Y/%m/%d%H: %M: %S'),
    #     "comment": "转账"
    # }
    # ret = wallet.transfer_money(B_pub_key, A_pub_key, amount, metadata=meta)
    # if not ret["ret"]:
    #     print(ret["err"])
    # time_B = time.time()
    # print("Money transfer time: %f" % (time_B - time_A))
    # print("A's money: ")
    # time_A = time.time()
    # money_A_step3 = wallet.get_total_money(A_pub_key)
    # print("Total: " + str(money_A_step2))
    # time_B = time.time()
    # print("A's money query time: %f" % (time_B - time_A))
    # print("B's money: ")
    # money_B_step3 = wallet.get_total_money(B_pub_key)
    # print("Total: " + str(money_B_step2))
    # time_C = time.time()
    # print("B's money query time: %f" % (time_C - time_B))
    # if money_B_step2 - money_B_step3 == amount and money_A_step3 - money_A_step2 == amount:
    #     print("Check pass")
    # else:
    #     print("Check fail")
    # print("--------------------------------")


    # print("------------test rollback-------------")
    # print("At the beginning:")
    # print("A's money: ")
    # time_A = time.time()
    # money_A_begin = wallet.get_total_money(A_pub_key)
    # print("Total: " + str(money_A_begin))
    # time_B = time.time()
    # print("A's money query time: %f" % (time_B - time_A))
    # for i in range(10):
    #     print('-------for-------- %d ---'%i)
    #     amount = 9
    #     print("Deposit to A: $%d" % amount)
    #     time_A = time.time()
    #     meta = {
    #         "from": {
    #             "name": "张三",
    #             "bank": "招商银行",
    #             "account": "6214888888888888"
    #         },
    #         "time": datetime.datetime.now().strftime('%Y/%m/%d%H: %M: %S'),
    #         "comment": "房租"
    #     }
    #     ret = wallet.deposit_money(A_pub_key, amount, metadata=meta)
    #     if not ret["ret"]:
    #         print(ret["err"])
    #     time_B = time.time()
    #     print("A's deposit time: %f" % (time_B - time_A))
    #     print("A's money: ")
    #     time_A = time.time()
    #     money_A_step1 = wallet.get_total_money(A_pub_key)
    #     print("Total: " + str(money_A_step1))
    #     time_B = time.time()
    #     print("A's money query time: %f" % (time_B - time_A))
    #     print('-------for  over-----------')
    # print('-------transaction-----------')
    # amount = 10
    # print("A pays to B: $%d" % amount)
    # time_A = time.time()
    # meta = {
    #     "from": {
    #         "name": "张三",
    #         "phone": "13700000000"
    #     },
    #     "to": {
    #         "name": "李四",
    #         "bank": "招商银行",
    #         "account": "62140000000000000"
    #     },
    #     "time": datetime.datetime.now().strftime('%Y/%m/%d%H: %M: %S'),
    #     "comment": "转账"
    # }
    # ret = wallet.transfer_money(A_pub_key, wallet.BLACKHOLE_PUB_KEY, amount, metadata=meta)
    # if not ret["ret"]:
    #     print(ret["err"])
    # time_B = time.time()
    # print("Money transfer time: %f" % (time_B - time_A))
    # print("A's money: ")
    # time_A = time.time()
    # money_A_step2 = wallet.get_total_money(A_pub_key)
    # print("Total: " + str(money_A_step2))
    # time_B = time.time()
    # print("A's money query time: %f" % (time_B - time_A))


    # total = wallet.get_total_money(B_pub_key)
    # print('total', total)

    # meta = {
    #     "from": {
    #         "name": "张三",
    #         "phone": "13700000000"
    #     },
    #     "to": {
    #         "name": "李四",
    #         "phone": "13800000000"
    #     },
    #     "time": datetime.datetime.now().strftime('%Y/%m/%d%H: %M: %S'),
    #     "comment": "转账",
    #     "operation": "transfer"
    # }
    # ret = wallet.transfer_money(account_from=B_pub_key, account_to=A_pub_key, amount=total,
    #                             metadata=meta, keyfree=True)
    #
    # print('ret',ret)
